public without sharing class warrantyRegistrationController 
{
	public List<Purchased_Product__c> listPurchasedProducts  = new List<Purchased_Product__c>();
	public List<purchasedProductInfo> listpurchasedProductInfo {get;set;}
	public custInfo objCustomerInfo {get;set;}
	public Boolean bShowSuccess {get;set;}
	public Boolean bEdit {get;set;}
	public Boolean bConfirm {get;set;}
	public Boolean bTopTextVisible {get;set;}	
	public String strDealer {get;set;}
	private Account objAccount = new Account();
	private Map<Id, Account> mapFlatIds = new Map<Id, Account>();
	private Map<Id, Account> mapFloorIds = new Map<Id, Account>();
	private Map<Id, Account> mapTowerIds = new Map<Id, Account>();
	private List<Account> matchingFlatNos = new List<Account>();
	private List<Account> matchingFloorNos = new List<Account>();
	private List<Account> matchingTowerNos = new List<Account>();
	public List<SelectOption> DealerOptions {get;set;}
	public List<SelectOption> SalutationOptions {get;set;}
	public List<SelectOption> FlatOptions {get;set;}
	public List<SelectOption> TowerBlockOptions {get;set;}
	public List<SelectOption> DistrictOptions {get;set;}
	public List<SelectOption> CityOptions {get;set;}
	public List<SelectOption> CountryOptions {get;set;}
	private String strFlatNo = '';
	private String strFloorNo = '';
	private String strTowerBlockNo = '';
	private String strErrorMessage = '';
	private static final String strDefaultErrorMessage = 'We appear to be missing some information. Please fill in the required boxes. \r';
	private class WarrantyException extends Exception {}   
	public warrantyRegistrationController()
	{
		bShowSuccess = false;
		bEdit = true;
		bTopTextVisible = true;
		if(bConfirm == null) bConfirm = false;
		
		if(DealerOptions == null)
		{
			DealerOptions = populateDealerOptions();
		}
		if(SalutationOptions == null)
		{
			SalutationOptions = populateSalutationOptions();
		}
		if(FlatOptions == null)
		{
			FlatOptions = populateFlatOptions();
		}
		if(TowerBlockOptions == null)
		{
			TowerBlockOptions = populateTowerBlockOptions();
		}
		if(DistrictOptions == null)
		{
			DistrictOptions = populateDistrictOptions();
		}
		if(CityOptions == null)
		{
			CityOptions = populateCityOptions();
		}	
		if(CountryOptions == null)
		{
			CountryOptions = populateCountryOptions();
		} 
		
		if(objCustomerInfo == null)objCustomerInfo = new custInfo();		
		if(listpurchasedProductInfo == null) listpurchasedProductInfo = new List<purchasedProductInfo>();
		for(Integer i=0; i<5; i++)
		{
			purchasedProductInfo objPurchasedProductInfo = new purchasedProductInfo(i);
			objPurchasedProductInfo.proxyDatePurchaseObject = new Account();
			objPurchasedProductInfo.proxyDateDeliveryObject = new Account();
			objPurchasedProductInfo.purchasedProduct = new Purchased_Product__c();
			listpurchasedProductInfo.add(objPurchasedProductInfo);
		} 				
	}	  
	
	public List<SelectOption> populateDealerOptions() 
	{	      
		List<SelectOption> dealerOptions = new List<SelectOption>();
   		Schema.DescribeFieldResult fieldResult = Purchased_Product__c.Dealer_Retailer__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();     
   		for(Schema.PicklistEntry f : ple)
   		{
      		dealerOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return dealerOptions;
	}

	public List<SelectOption> populateSalutationOptions() 
		{	      
			List<SelectOption> salutationOptions = new List<SelectOption>();
			  
	   		Schema.DescribeFieldResult fieldResult = Account.Salutation.getDescribe();
	   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
	        salutationOptions.add(new SelectOption('','--None--'));
	   		for( Schema.PicklistEntry f : ple)
	   		{
	      		salutationOptions.add(new SelectOption(f.getValue(), f.getLabel()));
	   		}       
			return salutationOptions;
		} 	
		
	public List<SelectOption> populateFlatOptions()
	{
		List<SelectOption> flatOptions = new List<SelectOption>();
		  
   		Schema.DescribeFieldResult fieldResult = Account.Flat_Unit_Room_Suite__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
   		for( Schema.PicklistEntry f : ple)
   		{
      		flatOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return flatOptions;
	} 
	
	public List<SelectOption> populateTowerBlockOptions()
	{
		List<SelectOption> towerBlockOptions = new List<SelectOption>();
		  
   		Schema.DescribeFieldResult fieldResult = Account.Block_Tower_House_Shop_Lot_Billing__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
   		for( Schema.PicklistEntry f : ple)
   		{
      		towerBlockOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return towerBlockOptions;
	} 
	
	public List<SelectOption> populateDistrictOptions()
	{
		List<SelectOption> districtOptions = new List<SelectOption>();
		  
   		Schema.DescribeFieldResult fieldResult = Account.District_Billing__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
   		for( Schema.PicklistEntry f : ple)
   		{
      		districtOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return districtOptions;
	}
	
	public List<SelectOption> populateCityOptions()
	{
		List<SelectOption> cityOptions = new List<SelectOption>();
		  
   		Schema.DescribeFieldResult fieldResult = Account.City_Billing__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
   		for( Schema.PicklistEntry f : ple)
   		{
      		cityOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return cityOptions;
	}
	
	public List<SelectOption> populateCountryOptions()
	{
		List<SelectOption> countryOptions = new List<SelectOption>();
		Schema.DescribeFieldResult fieldResult = Account.Country_Billing__c.getDescribe();
   		List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
   		for( Schema.PicklistEntry f : ple)
   		{
      		countryOptions.add(new SelectOption(f.getValue(), f.getLabel()));
   		}       
		return countryOptions;	
	}
		
	public PageReference doCancel()
	{
		bEdit = true;
		return null;
	}
	
	public PageReference doSubmit()
	{	
		Boolean bHasAtLeastOneProduct = false;
		for(Integer k=0;k<listpurchasedProductInfo.size();k++)
		{	
			listpurchasedProductInfo[k].purchasedProduct.Purchase_Date__c = null;
			listpurchasedProductInfo[k].purchasedProduct.Delivery_Date__c = null;
			
			if(listpurchasedProductInfo[k].proxyDatePurchaseObject != null && listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate != null)
			{
				listpurchasedProductInfo[k].purchasedProduct.Purchase_Date__c = listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate;		
			}		
			if(listpurchasedProductInfo[k].proxyDateDeliveryObject != null && listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate != null)
			{
				listpurchasedProductInfo[k].purchasedProduct.Delivery_Date__c = listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate;		
			}		
			if(listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate != null &&
			   listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate != null &&
			   listpurchasedProductInfo[k].purchasedProduct.Product_Type__c == null)
			{
				strErrorMessage = '- Product Type is required.';
				if(!ApexPages.hasMessages())
				{
					ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
					ApexPages.addMessage(pMessage);
				}
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
				ApexPages.addMessage(pMessage);
			}
			if(listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate == null &&
				listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate != null && 
				listpurchasedProductInfo[k].purchasedProduct.Product_Type__c != null)
			{
				strErrorMessage = '- Date of Purchase is required.';
				if(!ApexPages.hasMessages())
				{
					ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
					ApexPages.addMessage(pMessage); 
				}				
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
				ApexPages.addMessage(pMessage);
			}
			if(listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate != null &&
				listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate == null && 
				listpurchasedProductInfo[k].purchasedProduct.Product_Type__c != null)
			{
				strErrorMessage = '- Date of Delivery is required.';
				if(!ApexPages.hasMessages())
				{
					ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
					ApexPages.addMessage(pMessage); 
				}				
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
				ApexPages.addMessage(pMessage);
			}
			if(listpurchasedProductInfo[k].proxyDatePurchaseObject.PersonBirthdate != null && 
				listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate != null &&
				listpurchasedProductInfo[k].purchasedProduct.Product_Type__c != null)
			{
				bHasAtLeastOneProduct = true;
			}
		}
		if(!bHasAtLeastOneProduct)
		{
			strErrorMessage = '- No Purchased Product Information Supplied.';
			if(!ApexPages.hasMessages())
			{
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
				ApexPages.addMessage(pMessage);
			}			
			ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
			ApexPages.addMessage(pMessage);
		}
		if(objCustomerInfo.acct.FirstName == '')
		{
			strErrorMessage = '- First Name is required.';
			if(!ApexPages.hasMessages())
			{
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
				ApexPages.addMessage(pMessage);
			}			
			ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
			ApexPages.addMessage(pMessage);
		}
		if(objCustomerInfo.acct.LastName == '')
		{
			strErrorMessage = '- Last Name is required.';
			if(!ApexPages.hasMessages())
			{
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
				ApexPages.addMessage(pMessage);
			}			
			ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
			ApexPages.addMessage(pMessage);
		}	
		if(objCustomerInfo.acct.Phone == '')
		{
			strErrorMessage = '- Telephone Number is required.';
			if(!ApexPages.hasMessages())
			{
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strDefaultErrorMessage);
				ApexPages.addMessage(pMessage);
			}				
			ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, strErrorMessage);
			ApexPages.addMessage(pMessage);
		}
		bEdit = false;
		if(ApexPages.hasMessages())
		{
			bEdit = true;
		}
		return null;
	}
	
	public PageReference doConfirm()
	{
		listPurchasedProducts = new List<Purchased_Product__c>();
		objAccount = objCustomerInfo.acct;
		
		for(Integer k=0;k<listpurchasedProductInfo.size();k++)
		{
			if(listpurchasedProductInfo[k].purchasedProduct.Purchase_Date__c != null && 
				listpurchasedProductInfo[k].purchasedProduct.Product_Type__c != null &&
				listpurchasedProductInfo[k].proxyDateDeliveryObject.PersonBirthdate != null)
			{
				listPurchasedProducts.add(listpurchasedProductInfo[k].purchasedProduct);
			}	
		}
		if(listPurchasedProducts.size() > 0)
		{
			try 
			{
				Id acctId;
				if (objAccount != null)
				{
					objAccount.PersonHasOptedOutOfEmail = !objAccount.PersonHasOptedOutOfEmail;
					if(objAccount.Flat_No__c == null)
					{
						objAccount.Flat_No__c = '';
					}
					if(objAccount.Floor_No__c == null)
					{
						objAccount.Floor_No__c = '';
					}	
					if(objAccount.Tower_Block_No__c == null)
					{				
						objAccount.Tower_Block_No__c = '';
					}
					
					if(objAccount.Flat_No__c != '' && objAccount.Floor_No__c != '' && objAccount.Tower_Block_No__c != '')
					{
						strFlatNo = (objAccount.Flat_Unit_Room_Suite__c + ' ' + objAccount.Flat_No__c).trim();
						strFloorNo = (objAccount.Floor_No__c).trim();
						strTowerBlockNo = (objAccount.Block_Tower_House_Shop_Lot_Billing__c + ' ' + objAccount.Tower_Block_No__c).trim(); 
						
						matchingFlatNos = [select id, Address_1_indexed__c, Address_2_indexed__c, Address_3_indexed__c from Account 
												where Address_1_indexed__c like :('%' + strFlatNo + '%') or 
												Address_2_indexed__c like :('%' + strFlatNo + '%') or 
												Address_3_indexed__c like :('%' + strFlatNo + '%') limit 1000];						

						matchingFloorNos = [select id, Address_1_indexed__c, Address_2_indexed__c, Address_3_indexed__c from Account 
												where Address_1_indexed__c like :('%' + strFloorNo + '%') or
												Address_2_indexed__c like :('%' + strFloorNo + '%') or 
												Address_3_indexed__c like :('%' + strFloorNo + '%') limit 1000];
						
						matchingTowerNos = [select id, Address_1_indexed__c, Address_2_indexed__c, Address_3_indexed__c from Account 
												where Address_1_indexed__c like :('%' + strTowerBlockNo + '%') or
												Address_2_indexed__c like :('%' + strTowerBlockNo + '%') or 
												Address_3_indexed__c like :('%' + strTowerBlockNo + '%') limit 1000];
					}							
								
					if(matchingFlatNos.size()>0 && matchingFloorNos.size()>0 && matchingTowerNos.size()>0)
					{				
						objAccount.Duplicate__c = true;			
						for(Account acct: matchingFlatNos)
						{
							mapFlatIds.put(acct.Id, acct);
						}	
						for(Account acct: matchingFloorNos)
						{
							mapFloorIds.put(acct.Id, acct);
						}
						for(Account acct: matchingTowerNos)
						{
							mapTowerIds.put(acct.Id, acct);
						}		
						Map<Id, Account> mapAccounts = new Map<Id, Account>([Select Id from Account where
													  Id in :mapFlatIds.keySet() or
													  Id in :mapFloorIds.keySet() or 
													  Id in :mapTowerIds.keySet() limit 1000]);
													  		
						for(Account acct: mapAccounts.values())
						{
							if(mapFlatIds.containsKey(acct.Id) && mapFloorIds.containsKey(acct.Id) && mapTowerIds.containsKey(acct.Id))
							{
								if(mapFlatIds.get(acct.Id) == mapFloorIds.get(acct.Id) && mapFloorIds.get(acct.Id) == mapTowerIds.get(acct.Id))
								{
									objAccount.Duplicate_Reason__c = 'Address Match with Id: ' + String.valueOf(acct.Id);
									break;									
								}
							}
						}
					}
					objAccount.Address_1_indexed__c = strFlatNo + '-' + strFloorNo + '-' + strTowerBlockNo;
					objAccount.Address_2_indexed__c = objAccount.Building_Name_Billing__c;
					objAccount.Address_3_indexed__c = objAccount.Street_Name_Billing__c;
					//objAccount.BillingStreet = objAccount.Address_1_indexed__c + ', ' + objAccount.Address_2_indexed__c + ', ' + objAccount.Address_3_indexed__c;
					Database.SaveResult saveResult = database.insert(objAccount);	
					if(saveResult.isSuccess()) acctId = saveResult.getId();
				}					
				for(Integer k=0; k<listPurchasedProducts.size(); k++)
				{
					listPurchasedProducts[k].Account__c = acctId;
					listPurchasedProducts[k].Dealer_Retailer__c = strDealer;
					listPurchasedProducts[k].Registration_Date__c = Date.today();
					listPurchasedProducts[k].Warranty_Type__c = 'MG';
				}
				database.insert(listPurchasedProducts);
				bShowSuccess = true;		
				bTopTextVisible = false;
	
			}
			catch(DMLException ex)
			{ 
				for (Integer i = 0; i < ex.getNumDml(); i++) 
				{
					if(ex.getDmlType(i) == System.Statuscode.FIELD_CUSTOM_VALIDATION_EXCEPTION)
					{
						ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, ex.getDmlMessage(i));
						ApexPages.addMessage(pMessage);				
					}
				}
			}		
			catch(Exception ex)
			{
				ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, ex.getMessage());
				ApexPages.addMessage(pMessage);
			}
		}
		else
		{
			ApexPages.Message pMessage = new ApexPages.Message(ApexPages.Severity.FATAL, 'No Purchased Product Information Supplied.');
			ApexPages.addMessage(pMessage);
		}
		return null;
	}
	
	public class custInfo  
	{
		public Account acct{get;set;}	

		public custInfo()
		{
			RecordType recType = [Select Id from RecordType where Name = 'Person Account' or Name = 'Personal Account' limit 1];			
			acct = new Account(RecordTypeId = recType.Id, Created_Online__c = 'Web', Type = 'Customer');
		}		
	}	
	
	public class purchasedProductInfo
	{
		public String recCtr {get;set;}
		public Purchased_Product__c purchasedProduct {get;set;}	
		public Account proxyDatePurchaseObject {get;set;}
		public Account proxyDateDeliveryObject {get;set;}					
		public purchasedProductInfo(Integer intCtr)
		{
			recCtr = String.valueOf(intCtr);
		}
	}	
}